package org.loong.crypto.service.software.provider.asymmetric.rsa;

import java.security.interfaces.RSAPrivateKey;
import java.security.spec.PSSParameterSpec;

import org.apache.commons.lang3.StringUtils;
import org.loong.crypto.common.exception.CryptoException;
import org.loong.crypto.common.exception.InvalidKeyException;
import org.loong.crypto.core.algorithm.SignatureAlgorithm;
import org.loong.crypto.core.utils.RSAKeyUtils;
import org.loong.crypto.service.core.provider.Signer;
import org.loong.crypto.service.core.provider.impl.RSAProvider;

import cn.hutool.crypto.asymmetric.Sign;

/**
 * RSA signer of data.
 */
public class RSASigner extends RSAProvider implements Signer {

    /**
     * The private key.
     */
    private RSAPrivateKey privateKey;

    /**
     * Creates a new signer.
     *
     * @param keyBytes the private key bytes. Must not be {@code null}.
     */
    public RSASigner(final byte[] keyBytes) {
        this(RSAKeyUtils.toRSAPrivateKey(keyBytes));
    }

    /**
     * Creates a new signer.
     *
     * @param privateKey the private key. Must not be {@code null}.
     */
    public RSASigner(final RSAPrivateKey privateKey) {
        if (privateKey == null) {
            throw new InvalidKeyException("The private RSA key must not be null.");
        }

        if (!"RSA".equalsIgnoreCase(privateKey.getAlgorithm())) {
            throw new InvalidKeyException("The private key algorithm must be RSA.");
        }

        this.privateKey = privateKey;
    }

    @Override
    public byte[] sign(final SignatureAlgorithm algorithm, final byte[] data) throws CryptoException {
        try {
            Sign signature = new Sign(algorithm.getName(), privateKey, null);
            if (StringUtils.endsWith(algorithm.getName(), "RSASSA-PSS")) {
                PSSParameterSpec pssSpec = getPSSParameterSpec(algorithm);
                if (pssSpec != null) {
                    signature.setParameter(pssSpec);
                }
            }
            return signature.sign(data);
        } catch (cn.hutool.crypto.CryptoException e) {
            throw new CryptoException("RSA signature exception: " + e.getMessage(), e);
        }
    }
}
